home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / htswizard.c < prev    next >
C/C++ Source or Header  |  2006-04-09  |  37KB  |  1,062 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       wizard system (accept/refuse links)                    */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. /* Internal engine bytecode */
  39. #define HTS_INTERNAL_BYTECODE
  40.  
  41. #include "htswizard.h"
  42. #include "htsdefines.h"
  43.  
  44. /* specific definitions */
  45. #include "htsbase.h"
  46. #include <ctype.h>
  47. /* END specific definitions */
  48.  
  49. // version 1 pour httpmirror
  50. // flusher si on doit lire peu α peu le fichier
  51. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  52.  
  53. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  54. #define urladr   (liens[ptr]->adr)
  55. #define urlfil   (liens[ptr]->fil)
  56.  
  57. // libΘrer filters[0] pour insΘrer un ΘlΘment dans filters[0]
  58. #define HT_INSERT_FILTERS0 do {\
  59.   int i;\
  60.   if (*opt->filters.filptr > 0) {\
  61.     for(i = (*opt->filters.filptr)-1 ; i>=0 ; i--) {\
  62.       strcpybuff((*opt->filters.filters)[i+1],(*opt->filters.filters)[i]);\
  63.     }\
  64.   }\
  65.   (*opt->filters.filters)[0][0]='\0';\
  66.   (*opt->filters.filptr)++;\
  67.   assertf((*opt->filters.filptr) < opt->maxfilter); \
  68. } while(0)
  69.  
  70. typedef struct htspair_t {
  71.     char *tag;
  72.     char *attr;
  73. } htspair_t;
  74.  
  75. /* "embedded" */
  76. htspair_t hts_detect_embed[] = {
  77.     { "img", "src" },
  78.     { "link", "href" },
  79.  
  80.     /* embedded script hack */
  81.     { "script", ".src" },
  82.  
  83.     /* style */
  84.     { "style", "import" },
  85.  
  86.     { NULL, NULL }
  87. };
  88.  
  89. /* Internal */
  90. static int hts_acceptlink_(httrackp* opt,
  91.                                                     int ptr,int lien_tot,lien_url** liens,
  92.                                                     char* adr,char* fil,
  93.                                                     char* tag, char* attribute,
  94.                                                     int* set_prio_to,
  95.                                                     int* just_test_it);
  96.  
  97. /*
  98. httrackp opt     bloc d'options
  99. int ptr,int lien_tot,lien_url** liens
  100.                              relatif aux liens
  101. char* adr,char* fil
  102.                              adresse/fichier α tester
  103. char** filters,int filptr,int filter_max
  104.                              relatif aux filtres
  105. robots_wizard* robots
  106.                              relatif aux robots
  107. int* set_prio_to
  108.                              callback obligatoire "capturer ce lien avec prio=N-1"
  109. int* just_test_it
  110.                              callback optionnel "ne faire que tester ce lien Θventuellement"
  111. retour:
  112. 0 acceptΘ
  113. 1 refusΘ
  114. -1 pas d'avis
  115. */
  116.  
  117. int hts_acceptlink(httrackp* opt,
  118.                                      int ptr,int lien_tot,lien_url** liens,
  119.                                      char* adr,char* fil,
  120.                                      char* tag, char* attribute,
  121.                                      int* set_prio_to,
  122.                                      int* just_test_it) 
  123. {
  124.     int forbidden_url = hts_acceptlink_(opt, ptr, lien_tot, liens,
  125.         adr, fil, tag, attribute, set_prio_to, just_test_it);
  126.     int prev_prio = set_prio_to ? *set_prio_to : 0;
  127.  
  128.     // -------------------- PHASE 6 --------------------
  129. #if HTS_ANALYSTE
  130.     if (hts_htmlcheck_check != NULL) {
  131.         int test_url = hts_htmlcheck_check(adr, fil, forbidden_url);
  132.         if (test_url != -1) {
  133.             forbidden_url = test_url;
  134.             if (set_prio_to)
  135.                 *set_prio_to = prev_prio;
  136.         }
  137.     }
  138. #endif
  139.  
  140.     return forbidden_url;
  141. }
  142.  
  143. static int cmp_token(const char *tag, const char *cmp) {
  144.     int p;
  145.     return (strncasecmp(tag, cmp, ( p = (int) strlen(cmp) ) ) == 0
  146.         && !isalnum((unsigned char) tag[p]));
  147. }
  148.  
  149. static int hts_acceptlink_(httrackp* opt,
  150.                                                     int ptr,int lien_tot,lien_url** liens,
  151.                                                     char* adr,char* fil,
  152.                                                     char* tag, char* attribute,
  153.                                                     int* set_prio_to,
  154.                                                     int* just_test_it) 
  155. {
  156.   int forbidden_url=-1;
  157.   int meme_adresse;
  158.     int embedded_triggered = 0;
  159. #define _FILTERS     (*opt->filters.filters)
  160. #define _FILTERS_PTR (opt->filters.filptr)
  161. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  162.   int may_set_prio_to=0;
  163.  
  164.   // -------------------- PHASE 0 --------------------
  165.  
  166.   /* Infos */
  167.   if ((opt->debug>1) && (opt->log!=NULL)) {
  168.     fspc(opt->log,"debug"); fprintf(opt->log,"wizard test begins: %s%s"LF,adr,fil);
  169.     test_flush;
  170.   }
  171.   
  172.   /* Already exists? Then, we know that we knew that this link had to be known */
  173.   if (adr[0] != '\0'
  174.     && fil[0] != '\0'
  175.     && opt->hash != NULL
  176.     && hash_read((hash_struct*)opt->hash, adr, fil, 1, opt->urlhack) >= 0
  177.     ) {
  178.     return 0;  /* Yokai */
  179.   }
  180.   
  181.   // -------------------- PRELUDE OF PHASE 3-BIS --------------------
  182.  
  183.     /* Built-in known tags (<img src=..>, ..) */
  184.     if (forbidden_url != 0 && opt->nearlink && tag != NULL && attribute != NULL) {
  185.         int i;
  186.         for(i = 0 ; hts_detect_embed[i].tag != NULL ; i++) {
  187.             if (cmp_token(tag, hts_detect_embed[i].tag)
  188.                 && cmp_token(attribute, hts_detect_embed[i].attr)
  189.                 ) 
  190.             {
  191.                 embedded_triggered = 1;
  192.                 break;
  193.             }
  194.         }
  195.     }
  196.  
  197.  
  198.   // -------------------- PHASE 1 --------------------
  199.  
  200.   /* Doit-on traiter les non html? */
  201.   if ((opt->getmode & 2)==0) {    // non on ne doit pas
  202.     if (!ishtml(fil)) {  // non il ne faut pas
  203.       //adr[0]='\0';    // ne pas traiter ce lien, pas traiter
  204.       forbidden_url=1;    // interdire rΘcupΘration du lien
  205.       if ((opt->debug>1) && (opt->log!=NULL)) {
  206.         fspc(opt->log,"debug"); fprintf(opt->log,"non-html file ignored at %s : %s"LF,adr,fil);
  207.         test_flush;
  208.       }
  209.       
  210.     }
  211.   }
  212.   
  213.   /* Niveau 1: ne pas parser suivant! */
  214.   if (ptr>0) {
  215.     if ( ( liens[ptr]->depth <= 0 ) || ( liens[ptr]->depth <= 1 && !embedded_triggered ) ) {
  216.       forbidden_url=1;    // interdire rΘcupΘration du lien
  217.       if ((opt->debug>1) && (opt->log!=NULL)) {
  218.         fspc(opt->log,"debug"); fprintf(opt->log,"file from too far level ignored at %s : %s"LF,adr,fil);
  219.         test_flush;
  220.       }
  221.     }
  222.   }
  223.  
  224.   /* en cas d'Θchec en phase 1, retour immΘdiat! */
  225.   if (forbidden_url == 1) {
  226.     return forbidden_url;
  227.   }
  228.   
  229.   // -------------------- PHASE 2 --------------------
  230.  
  231.   // ------------------------------------------------------
  232.   // doit-on traiter ce lien?.. vΘrifier droits de dΘplacement
  233.   meme_adresse=strfield2(adr,urladr);
  234.   if ((opt->debug>1) && (opt->log!=NULL)) {
  235.     fspc(opt->log,"debug"); 
  236.     if (meme_adresse) 
  237.       fprintf(opt->log,"Compare addresses: %s=%s"LF,adr,urladr);
  238.     else
  239.       fprintf(opt->log,"Compare addresses: %s!=%s"LF,adr,urladr);
  240.     test_flush;
  241.   }
  242.   if (meme_adresse) {  // mΩme adresse 
  243.     {  // tester interdiction de descendre
  244.       // MODIFIE : en cas de remontΘe puis de redescente, il se pouvait qu'on ne puisse pas atteindre certains fichiers
  245.       // problΦme: si un fichier est virtuellement accessible via une page mais dont le lien est sur une autre *uniquement*..
  246.       char BIGSTK tempo[HTS_URLMAXSIZE*2];
  247.       char BIGSTK tempo2[HTS_URLMAXSIZE*2];
  248.       tempo[0] = tempo2[0] = '\0';
  249.       
  250.       // note (up/down): on calcule α partir du lien primaire, ET du lien prΘcΘdent.
  251.       // ex: si on descend 2 fois on peut remonter 1 fois
  252.       
  253.       if (lienrelatif(tempo,fil,liens[liens[ptr]->premier]->fil)==0) {
  254.         if (lienrelatif(tempo2,fil,liens[ptr]->fil)==0) {
  255.           if ((opt->debug>1) && (opt->log!=NULL)) {
  256.             fspc(opt->log,"debug"); fprintf(opt->log,"build relative links to test: %s %s (with %s and %s)"LF,tempo,tempo2,liens[liens[ptr]->premier]->fil,liens[ptr]->fil);
  257.             test_flush;
  258.           }
  259.           
  260.           // si vient de primary, ne pas tester lienrelatif avec (car host "diffΘrent")
  261.           /*if (liens[liens[ptr]->premier] == 0) {   // vient de primary
  262.           }
  263.           */
  264.           
  265.           // NEW: finalement OK, sauf pour les moved repΘrΘs par link_import
  266.           // PROBLEME : annulΘ a cause d'un lien Θventuel isolΘ acceptΘ..qui entrainerait un miroir
  267.           
  268.           // (test mΩme niveau (NOUVEAU α cause de certains problΦmes de filtres non intΘgrΘs))
  269.           // NEW
  270.           if ( 
  271.             (tempo[0]  != '\0' && tempo[1]  != '\0' && strchr(tempo+1,'/') == 0)
  272.             ||
  273.             (tempo2[0] != '\0' && tempo2[1] != '\0' && strchr(tempo2+1,'/') == 0) 
  274.             ) {
  275.             if (!liens[ptr]->link_import) {   // ne rΘsulte pas d'un 'moved'
  276.               forbidden_url=0;
  277.               if ((opt->debug>1) && (opt->log!=NULL)) {
  278.                 fspc(opt->log,"debug"); fprintf(opt->log,"same level link authorized: %s%s"LF,adr,fil);
  279.                 test_flush;
  280.              }
  281.             }
  282.           }
  283.           
  284.           // down
  285.           if ( (strncmp(tempo,"../",3)) || (strncmp(tempo2,"../",3)))  {   // pas montΘe sinon ne nbous concerne pas
  286.             int test1,test2;
  287.             if (!strncmp(tempo,"../",3))
  288.               test1=0;
  289.             else
  290.               test1 = (strchr(tempo +((*tempo =='/')?1:0),'/')!=NULL);
  291.             if (!strncmp(tempo2,"../",3))
  292.               test2=0;
  293.             else
  294.               test2 = (strchr(tempo2+((*tempo2=='/')?1:0),'/')!=NULL);
  295.             if ( (test1) && (test2) ) {   // on ne peut que descendre
  296.               if ((opt->seeker & 1)==0) {  // interdiction de descendre
  297.                 forbidden_url=1;
  298.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  299.                   fspc(opt->log,"debug"); fprintf(opt->log,"lower link canceled: %s%s"LF,adr,fil);
  300.                   test_flush;
  301.                 }
  302.               } else {    // autorisΘ α priori - NEW
  303.                 if (!liens[ptr]->link_import) {   // ne rΘsulte pas d'un 'moved'
  304.                   forbidden_url=0;
  305.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  306.                     fspc(opt->log,"debug"); fprintf(opt->log,"lower link authorized: %s%s"LF,adr,fil);
  307.                     test_flush;
  308.                   }
  309.                 }
  310.               }
  311.             } else if ( (test1) || (test2) ) {   // on peut descendre pour accΘder au lien
  312.               if ((opt->seeker & 1)!=0) {  // on peut descendre - NEW
  313.                 if (!liens[ptr]->link_import) {   // ne rΘsulte pas d'un 'moved'
  314.                   forbidden_url=0;
  315.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  316.                     fspc(opt->log,"debug"); fprintf(opt->log,"lower link authorized: %s%s"LF,adr,fil);
  317.                     test_flush;
  318.                   }
  319.                 }
  320.               }
  321.             }
  322.           }
  323.           
  324.           
  325.           // up
  326.           if ( (!strncmp(tempo,"../",3)) && (!strncmp(tempo2,"../",3)) ) {    // impossible sans monter
  327.             if ((opt->seeker & 2)==0) {  // interdiction de monter
  328.               forbidden_url=1;
  329.               if ((opt->debug>1) && (opt->log!=NULL)) {
  330.                 fspc(opt->log,"debug"); fprintf(opt->log,"upper link canceled: %s%s"LF,adr,fil);
  331.                 test_flush;
  332.               }
  333.             } else {       // autorisΘ α monter - NEW
  334.               if (!liens[ptr]->link_import) {   // ne rΘsulte pas d'un 'moved'
  335.                 forbidden_url=0;
  336.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  337.                   fspc(opt->log,"debug"); fprintf(opt->log,"upper link authorized: %s%s"LF,adr,fil);
  338.                   test_flush;
  339.                 }
  340.               }
  341.             }
  342.           } else if ( (!strncmp(tempo,"../",3)) || (!strncmp(tempo2,"../",3)) ) {    // Possible en montant
  343.             if ((opt->seeker & 2)!=0) {  // autorisΘ α monter - NEW
  344.               if (!liens[ptr]->link_import) {   // ne rΘsulte pas d'un 'moved'
  345.                 forbidden_url=0;
  346.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  347.                   fspc(opt->log,"debug"); fprintf(opt->log,"upper link authorized: %s%s"LF,adr,fil);
  348.                   test_flush;
  349.                 }
  350.               }
  351.             }  // sinon autorisΘ en descente
  352.           }
  353.           
  354.           
  355.         } else {
  356.           if (opt->errlog) {
  357.             fprintf(opt->errlog,"Error building relative link %s and %s"LF,fil,liens[ptr]->fil);
  358.             test_flush;
  359.           }
  360.         }
  361.       } else {
  362.         if (opt->errlog) {
  363.           fprintf(opt->errlog,"Error building relative link %s and %s"LF,fil,liens[liens[ptr]->premier]->fil);
  364.           test_flush;
  365.         }
  366.       }
  367.       
  368.     }  // tester interdiction de descendre?
  369.     
  370.     {  // tester interdiction de monter
  371.       char BIGSTK tempo[HTS_URLMAXSIZE*2];
  372.       char BIGSTK tempo2[HTS_URLMAXSIZE*2];
  373.       if (lienrelatif(tempo,fil,liens[liens[ptr]->premier]->fil)==0) {
  374.         if (lienrelatif(tempo2,fil,liens[ptr]->fil)==0) {
  375.         } else {
  376.           if (opt->errlog) { 
  377.             fprintf(opt->errlog,"Error building relative link %s and %s"LF,fil,liens[ptr]->fil);
  378.             test_flush;
  379.           }
  380.           
  381.         }
  382.       } else {
  383.         if (opt->errlog) { 
  384.           fprintf(opt->errlog,"Error building relative link %s and %s"LF,fil,liens[liens[ptr]->premier]->fil);
  385.           test_flush;
  386.         }
  387.         
  388.       }
  389.     }   // fin tester interdiction de monter
  390.     
  391.   } else {    // adresse diffΘrente, sortir?
  392.     
  393.     //if (!opt->wizard) {    // mode non wizard
  394.     // doit-on traiter ce lien?.. vΘrifier droits de sortie
  395.     switch((opt->travel & 255)) {
  396.     case 0: 
  397.       if (!opt->wizard)    // mode non wizard
  398.         forbidden_url=1; break;    // interdicton de sortir au dela de l'adresse
  399.     case 1: {              // sortie sur le mΩme dom.xxx
  400.       int i=strlen(adr)-1;
  401.       int j=strlen(urladr)-1;
  402.       while( (i>0) && (adr[i]!='.')) i--;
  403.       while( (j>0) && (urladr[j]!='.')) j--;
  404.       i--; j--;
  405.       while( (i>0) && (adr[i]!='.')) i--;
  406.       while( (j>0) && (urladr[j]!='.')) j--;
  407.       if ((i>0) && (j>0)) {
  408.         if (!strfield2(adr+i,urladr+j)) {   // !=
  409.           if (!opt->wizard) {   // mode non wizard
  410.             //printf("refused: %s\n",adr);
  411.             forbidden_url=1;  // pas mΩme domaine  
  412.             if ((opt->debug>1) && (opt->log!=NULL)) {
  413.               fspc(opt->log,"debug"); fprintf(opt->log,"foreign domain link canceled: %s%s"LF,adr,fil);
  414.               test_flush;
  415.             }
  416.           }
  417.           
  418.         } else {
  419.           if (opt->wizard) {   // mode wizard
  420.             forbidden_url=0;  // mΩme domaine  
  421.             if ((opt->debug>1) && (opt->log!=NULL)) {
  422.               fspc(opt->log,"debug"); fprintf(opt->log,"same domain link authorized: %s%s"LF,adr,fil);
  423.               test_flush;
  424.             }
  425.           }
  426.         }
  427.         
  428.       } else
  429.         forbidden_url=1;
  430.             } 
  431.       break;  
  432.     case 2: {                      // sortie sur le mΩme .xxx
  433.       int i=strlen(adr)-1;
  434.       int j=strlen(urladr)-1;
  435.       while( (i>0) && (adr[i]!='.')) i--;
  436.       while( (j>0) && (urladr[j]!='.')) j--;
  437.       if ((i>0) && (j>0)) {
  438.         if (!strfield2(adr+i,urladr+j)) {   // !-
  439.           if (!opt->wizard) {   // mode non wizard
  440.             //printf("refused: %s\n",adr);
  441.             forbidden_url=1;  // pas mΩme .xx  
  442.             if ((opt->debug>1) && (opt->log!=NULL)) {
  443.               fspc(opt->log,"debug"); fprintf(opt->log,"foreign location link canceled: %s%s"LF,adr,fil);
  444.               test_flush;
  445.             }
  446.           }
  447.         } else {
  448.           if (opt->wizard) {   // mode wizard
  449.             forbidden_url=0;  // mΩme domaine  
  450.             if ((opt->debug>1) && (opt->log!=NULL)) {
  451.               fspc(opt->log,"debug"); fprintf(opt->log,"same location link authorized: %s%s"LF,adr,fil);
  452.               test_flush;
  453.             }
  454.           }
  455.         }
  456.       } else forbidden_url=1;     
  457.             } 
  458.       break;
  459.     case 7:                 // everywhere!!
  460.       if (opt->wizard) {   // mode wizard
  461.         forbidden_url=0;
  462.         break;
  463.       }
  464.     }  // switch
  465.     
  466.     // ANCIENNE POS -- rΘcupΘrer les liens α c⌠tΘs d'un lien (nearlink)
  467.     
  468.   }  // fin test adresse identique/diffΘrente
  469.  
  470.   // -------------------- PHASE 3 --------------------
  471.  
  472.   // rΘcupΘrer les liens α c⌠tΘs d'un lien (nearlink) (nvelle pos)
  473.   if (forbidden_url != 0 && opt->nearlink) {
  474.     if (!ishtml(fil)) {  // non html
  475.       //printf("ok %s%s\n",ad,fil);
  476.       forbidden_url=0;    // autoriser
  477.       may_set_prio_to=1+1; // set prio to 1 (parse but skip urls) if near is the winner
  478.       if ((opt->debug>1) && (opt->log!=NULL)) {
  479.         fspc(opt->log,"debug"); fprintf(opt->log,"near link authorized: %s%s"LF,adr,fil);
  480.         test_flush;
  481.       }
  482.     }
  483.   }
  484.  
  485.   // -------------------- PHASE 3-BIS --------------------
  486.  
  487.     /* Built-in known tags (<img src=..>, ..) */
  488.     if (forbidden_url != 0 && embedded_triggered) {
  489.         forbidden_url=0;    // autoriser
  490.         may_set_prio_to=1+1; // set prio to 1 (parse but skip urls) if near is the winner
  491.         if ((opt->debug>1) && (opt->log!=NULL)) {
  492.             fspc(opt->log,"debug"); fprintf(opt->log,"near link authorized (friendly tag): %s%s"LF,adr,fil);
  493.             test_flush;
  494.         }
  495.     }
  496.  
  497.  
  498.   // -------------------- PHASE 4 --------------------
  499.   
  500.   // ------------------------------------------------------
  501.   // Si wizard, il se peut qu'on autorise ou qu'on interdise 
  502.   // un lien spΘcial avant mΩme de tester sa position, sa hiΘrarchie etc.
  503.   // peut court-circuiter le forbidden_url prΘcΘdent
  504.   if (opt->wizard) { // le wizard entre en action..
  505.     //
  506.     int question=1;         // poser une question                            
  507.     int force_mirror=0;     // pour mirror links
  508.     int filters_answer=0;   // dΘcision prise par les filtres
  509.     char BIGSTK l[HTS_URLMAXSIZE*2];
  510.     char BIGSTK lfull[HTS_URLMAXSIZE*2];
  511.     
  512.     if (forbidden_url!=-1) question=0;  // pas de question, rΘsolu
  513.     
  514.     // former URL complΦte du lien actuel
  515.     strcpybuff(l,jump_identification(adr));
  516.     if (*fil!='/') strcatbuff(l,"/");
  517.     strcatbuff(l,fil);
  518.     // full version (http://foo:bar@www.foo.com/bar.html)
  519.     if (!link_has_authority(adr))
  520.       strcpybuff(lfull,"http://");
  521.     else
  522.       lfull[0]='\0';
  523.     strcatbuff(lfull,adr);
  524.     if (*fil!='/') strcatbuff(lfull,"/");
  525.     strcatbuff(lfull,fil);
  526.     
  527.     // tester filters (URLs autorisΘes ou interdites explicitement)
  528.     
  529.     // si lien primaire on saute le joker, on est pas lΘmur
  530.     if (ptr==0) {  // lien primaire, autoriser
  531.       question=1;    // la question sera rΘsolue automatiquement
  532.       forbidden_url=0;
  533.       may_set_prio_to=0;    // clear may-set flag
  534.     } else {
  535.       // eternal depth first
  536.       // vΘrifier rΘcursivitΘ extΘrieure
  537.       if (opt->extdepth>0) {
  538.         if ( /*question && */ (ptr>0) && (!force_mirror)) {
  539.           // well, this is kinda a hak
  540.           // we don't want to mirror EVERYTHING, and we have to decide where to stop
  541.           // there is no way yet to tag "external" links, and therefore links that are
  542.           // "weak" (authorized depth < external depth) are just not considered for external
  543.           // hack
  544.           if (liens[ptr]->depth > opt->extdepth) {
  545.             // *set_prio_to = opt->extdepth + 1;
  546.             *set_prio_to = 1 + (opt->extdepth);
  547.             may_set_prio_to=0;  // clear may-set flag
  548.             forbidden_url=0;    // autorisΘ
  549.             question=0;         // rΘsolution auto
  550.             if ((opt->debug>1) && (opt->log!=NULL)) {
  551.               if (question) {
  552.                 fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) ambiguous link accepted (external depth): link %s at %s%s"LF,l,urladr,urlfil);
  553.               } else {
  554.                 fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) forced to accept link (external depth): link %s at %s%s"LF,l,urladr,urlfil);
  555.               }
  556.               test_flush;
  557.             }
  558.             
  559.           }
  560.         }
  561.       }  
  562.       
  563.       // filters
  564.       {
  565.         int jok;
  566.         char* mdepth="";
  567.         // filters, 0=sait pas 1=ok -1=interdit
  568.         {
  569.           int jokDepth1=0,jokDepth2=0;
  570.           int jok1=0,jok2=0;
  571.           jok1  = fa_strjoker(/*url*/0, _FILTERS,*_FILTERS_PTR,lfull,NULL,NULL,&jokDepth1);
  572.           jok2 =  fa_strjoker(/*url*/0, _FILTERS,*_FILTERS_PTR,l,    NULL,NULL,&jokDepth2);
  573.           if (jok2 == 0) {      // #2 doesn't know
  574.             jok = jok1;        // then, use #1
  575.             mdepth = _FILTERS[jokDepth1];
  576.           } else if (jok1 == 0) { // #1 doesn't know
  577.             jok = jok2;        // then, use #2
  578.             mdepth = _FILTERS[jokDepth2];
  579.           } else if (jokDepth1 >= jokDepth2) { // #1 matching rule is "after" #2, then it is prioritary
  580.             jok = jok1;
  581.             mdepth = _FILTERS[jokDepth1];
  582.           } else {                             // #2 matching rule is "after" #1, then it is prioritary
  583.             jok = jok2;
  584.             mdepth = _FILTERS[jokDepth2];
  585.           }
  586.         }
  587.         
  588.         if (jok == 1) {   // autorisΘ
  589.           filters_answer=1;  // dΘcision prise par les filtres
  590.           question=0;    // ne pas poser de question, autorisΘ
  591.           forbidden_url=0;  // URL autorisΘe
  592.           may_set_prio_to=0;    // clear may-set flag
  593.           if ((opt->debug>1) && (opt->log!=NULL)) {
  594.             fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) explicit authorized (%s) link: link %s at %s%s"LF,mdepth,l,urladr,urlfil);
  595.             test_flush;
  596.           }
  597.         } else if (jok == -1) {  // forbidden
  598.           filters_answer=1;  // dΘcision prise par les filtres
  599.           question=0;    // ne pas poser de question:
  600.           forbidden_url=1;   // URL interdite
  601.           if ((opt->debug>1) && (opt->log!=NULL)) {
  602.             fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) explicit forbidden (%s) link: link %s at %s%s"LF,mdepth,l,urladr,urlfil);
  603.             test_flush;
  604.           }
  605.         }  // sinon on touche α rien
  606.       }
  607.     }
  608.     
  609.     // vΘrifier mode mirror links
  610.     if (question) {
  611.       if (opt->mirror_first_page) {    // mode mirror links
  612.         if (liens[ptr]->precedent==0) {  // parent=primary!
  613.           forbidden_url=0;    // autorisΘ
  614.           may_set_prio_to=0;    // clear may-set flag
  615.           question=1;         // rΘsolution auto
  616.           force_mirror=5;     // mirror (5)
  617.           if ((opt->debug>1) && (opt->log!=NULL)) {
  618.             fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) explicit mirror link: link %s at %s%s"LF,l,urladr,urlfil);
  619.             test_flush;
  620.           }
  621.         }
  622.       }
  623.     }
  624.     
  625.     // on doit poser la question.. peut on la poser?
  626.     // (oui je sais quel preuve de dΘlicatesse, merci merci)      
  627.     if ((question) && (ptr>0) && (!force_mirror)) {
  628.       if (opt->wizard==2) {    // Θliminer tous les liens non rΘpertoriΘs comme autorisΘs (ou inconnus)
  629.         question=0;
  630.         forbidden_url=1;
  631.         if ((opt->debug>1) && (opt->log!=NULL)) {
  632.           fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) ambiguous forbidden link: link %s at %s%s"LF,l,urladr,urlfil);
  633.           test_flush;
  634.         }
  635.       }
  636.     }
  637.     
  638.     // vΘrifier robots.txt
  639.     if (opt->robots) {
  640.       int r = checkrobots(_ROBOTS,adr,fil);
  641.       if (r == -1) {    // interdiction
  642. #if DEBUG_ROBOTS
  643.         printf("robots.txt forbidden: %s%s\n",adr,fil);
  644. #endif
  645.         // question rΘsolue, par les filtres, et mode robot non strict
  646.         if ((!question) && (filters_answer) && (opt->robots == 1) && (forbidden_url!=1)) {
  647.           r=0;    // annuler interdiction des robots
  648.           if (!forbidden_url) {
  649.             if ((opt->debug>1) && (opt->log!=NULL)) {
  650.               fspc(opt->log,"debug"); fprintf(opt->log,"Warning link followed against robots.txt: link %s at %s%s"LF,l,adr,fil);
  651.               test_flush;
  652.             }
  653.           }
  654.         }
  655.         if (r == -1) {    // interdire
  656.           forbidden_url=1;
  657.           question=0;
  658.           if ((opt->debug>1) && (opt->log!=NULL)) {
  659.             fspc(opt->log,"debug"); fprintf(opt->log,"(robots.txt) forbidden link: link %s at %s%s"LF,l,adr,fil);
  660.             test_flush;
  661.           }
  662.         }
  663.       }
  664.     }
  665.     
  666.     if (!question) {
  667.       if ((opt->debug>1) && (opt->log!=NULL)) {
  668.         if (!forbidden_url) {
  669.           fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) shared foreign domain link: link %s at %s%s"LF,l,urladr,urlfil);
  670.         } else {
  671.           fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) cancelled foreign domain link: link %s at %s%s"LF,l,urladr,urlfil);
  672.         }
  673.         test_flush;
  674.       }
  675. #if BDEBUG==3
  676.       printf("at %s in %s, wizard says: url %s ",urladr,urlfil,l);
  677.       if (forbidden_url) printf("cancelled"); else printf(">SHARED<");
  678.       printf("\n");
  679. #endif 
  680.     }
  681.  
  682.     /* en cas de question, ou lien primaire (enregistrer autorisations) */
  683.     if (question || (ptr==0)) {
  684. #if HTS_ANALYSTE
  685.       char* s;
  686. #else
  687.       char s[4];
  688. #endif
  689.       int n=0;
  690.       
  691.       // si primaire (plus bas) alors ...
  692.       if ((ptr!=0) && (force_mirror==0)) {
  693.         HTS_REQUEST_START;
  694.         HT_PRINT("\n");
  695.         HT_PRINT("At "); HT_PRINT(urladr); HT_PRINT(", there is a link ("); HT_PRINT(adr); HT_PRINT("/"); HT_PRINT(fil); HT_PRINT(") which goes outside the address."LF);
  696.         HT_PRINT("What should I do? (press a key + enter)"LF LF);
  697.         HT_PRINT("* Ignore all further links" LF);
  698.         HT_PRINT("0 Ignore this link (default if empty entry)"LF);
  699.         HT_PRINT("1 Ignore directory and lower structures"LF);
  700.         HT_PRINT("2 Ignore all domain"LF);
  701.         //HT_PRINT("3 (Ignore location, not implemented)\n");
  702.         HT_PRINT(LF);
  703.         HT_PRINT("4 Get only this page/link"LF);
  704.         HT_PRINT("5 Mirror this link (useful)"LF);
  705.         HT_PRINT("6 Mirror links located in the same domain"LF);
  706.         HT_PRINT(LF);
  707. //#if HTS_ANALYSTE!=2
  708. //HT_PRINT("! View extract of html code where the link is located"LF);
  709. //#endif
  710.         HTS_REQUEST_END;
  711. #if HTS_ANALYSTE
  712.           {
  713.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  714.             tempo[0]='\0';
  715.             strcatbuff(tempo,adr);
  716.             strcatbuff(tempo,"/");
  717.             strcatbuff(tempo,fil);
  718.             s=hts_htmlcheck_query3(tempo);
  719.           }
  720. #else
  721.         do {
  722.           io_flush; linput(stdin,s,2);
  723. #endif
  724.           if (strnotempty(s)==0)  // entrΘe
  725.             n=0;
  726.           else if (isdigit((unsigned char)*s))
  727.             sscanf(s,"%d",&n);
  728.           else {
  729.             switch(*s) {
  730.             case '*': n=-1; break;
  731.             case '!': n=-999; {
  732.               /*char *a;
  733.               int i;                                    
  734.               a=copie_de_adr-128;
  735.               if (a<r.adr) a=r.adr;
  736.               for(i=0;i<256;i++) {
  737.                 if (a==copie_de_adr) printf("\nHERE:\n");
  738.                 printf("%c",*a++);
  739.               }
  740.               printf("\n\n");
  741.               */
  742.                       }
  743.               break;
  744.             default: n=-999; printf("What did you say?\n"); break;
  745.               
  746.             } 
  747.           }
  748. #if HTS_ANALYSTE
  749. #else
  750.         } while(n==-999);
  751. #endif
  752.         io_flush;
  753.       } else {   // lien primaire: autoriser rΘpertoire entier       
  754.         if (!force_mirror) {
  755.           if ((opt->seeker & 1)==0) {  // interdiction de descendre
  756.             n=7;
  757.           } else {
  758.             n=5;   // autoriser miroir rΘpertoires descendants (lien primaire)
  759.           }
  760.         } else   // forcer valeur (sub-wizard)
  761.           n=force_mirror;
  762.       }
  763.       
  764.       /* sanity check - reallocate filters HERE */
  765.       if ((*_FILTERS_PTR) + 1 >= opt->maxfilter) {
  766.         opt->maxfilter += HTS_FILTERSINC;
  767.         if (filters_init(&_FILTERS, opt->maxfilter, HTS_FILTERSINC) == 0) {
  768.           printf("PANIC! : Too many filters : >%d [%d]\n", (*_FILTERS_PTR),__LINE__);
  769.           fflush(stdout);
  770.           if (opt->errlog) {
  771.             fprintf(opt->errlog,LF"Too many filters, giving up..(>%d)"LF, (*_FILTERS_PTR) );
  772.             fprintf(opt->errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  773.             test_flush;
  774.           }
  775.           assertf("too many filters - giving up" == NULL);    // wild..
  776.         }
  777.       }
  778.  
  779.       // here we have enough room for a new filter if necessary
  780.       switch(n) {
  781.       case -1: // sauter tout le reste
  782.         forbidden_url=1;
  783.         opt->wizard=2;    // sauter tout le reste
  784.         break;
  785.       case 0:    // interdire les mΩmes liens: adr/fil
  786.         forbidden_url=1; 
  787.         HT_INSERT_FILTERS0;    // insΘrer en 0
  788.         strcpybuff(_FILTERS[0],"-");
  789.         strcatbuff(_FILTERS[0],jump_identification(adr));
  790.         if (*fil!='/') strcatbuff(_FILTERS[0],"/");
  791.         strcatbuff(_FILTERS[0],fil);
  792.         break;
  793.         
  794.       case 1: // Θliminer rΘpertoire entier et sous rΘp: adr/path/ *
  795.         forbidden_url=1;
  796.         {
  797.           int i=strlen(fil)-1;
  798.           while((fil[i]!='/') && (i>0)) i--;
  799.           if (fil[i]=='/') {
  800.             HT_INSERT_FILTERS0;    // insΘrer en 0
  801.             strcpybuff(_FILTERS[0],"-");
  802.             strcatbuff(_FILTERS[0],jump_identification(adr));
  803.             if (*fil!='/') strcatbuff(_FILTERS[0],"/");
  804.             strncatbuff(_FILTERS[0] ,fil,i);
  805.             if (_FILTERS[0][strlen(_FILTERS[0])-1]!='/') 
  806.               strcatbuff(_FILTERS[0],"/");
  807.             strcatbuff(_FILTERS[0],"*");
  808.           }
  809.         }            
  810.         
  811.         // ** ...
  812.         break;
  813.         
  814.       case 2:    // adresse adr*
  815.         forbidden_url=1;
  816.         HT_INSERT_FILTERS0;    // insΘrer en 0                                
  817.         strcpybuff(_FILTERS[0],"-");
  818.         strcatbuff(_FILTERS[0],jump_identification(adr));
  819.         strcatbuff(_FILTERS[0],"*");
  820.         break;
  821.         
  822.       case 3: // ** A FAIRE
  823.         forbidden_url=1;
  824.         /*
  825.         {
  826.         int i=strlen(adr)-1;
  827.         while((adr[i]!='/') && (i>0)) i--;
  828.         if (i>0) {
  829.         
  830.           }
  831.           
  832.       }*/
  833.         
  834.         break;
  835.         //
  836.       case 4:    // same link
  837.         // PAS BESOIN!!
  838.         /*HT_INSERT_FILTERS0;    // insΘrer en 0                                
  839.         strcpybuff(_FILTERS[0],"+");
  840.         strcatbuff(_FILTERS[0],adr);
  841.         if (*fil!='/') strcatbuff(_FILTERS[0],"/");
  842.         strcatbuff(_FILTERS[0],fil);*/
  843.         
  844.         
  845.         // Θtant donnΘ le renversement wizard/primary filter (les primary autorisent up/down ET interdisent)
  846.         // il faut Θviter d'un lien isolΘ effectue un miroir total..
  847.         
  848.         *set_prio_to = 0+1;    // niveau de rΘcursion=0 (pas de miroir)
  849.         
  850.         break;
  851.         
  852.       case 5:    // autoriser rΘpertoire entier et fils
  853.         if ((opt->seeker & 2)==0) {  // interdiction de monter
  854.           int i=strlen(fil)-1;
  855.           while((fil[i]!='/') && (i>0)) i--;
  856.           if (fil[i]=='/') {
  857.             HT_INSERT_FILTERS0;    // insΘrer en 0                                
  858.             strcpybuff(_FILTERS[0],"+");
  859.             strcatbuff(_FILTERS[0],jump_identification(adr));
  860.             if (*fil!='/') strcatbuff(_FILTERS[0],"/");
  861.             strncatbuff(_FILTERS[0],fil,i+1);
  862.             strcatbuff(_FILTERS[0],"*");
  863.           }
  864.         } else {    // autoriser domaine alors!!
  865.           HT_INSERT_FILTERS0;    // insΘrer en 0                                strcpybuff(filters[filptr],"+");
  866.           strcpybuff(_FILTERS[0],"+");
  867.           strcatbuff(_FILTERS[0],jump_identification(adr));
  868.           strcatbuff(_FILTERS[0],"*");
  869.         }
  870.         break;
  871.         
  872.       case 6:    // same domain
  873.         HT_INSERT_FILTERS0;    // insΘrer en 0                                strcpybuff(filters[filptr],"+");
  874.         strcpybuff(_FILTERS[0],"+");
  875.         strcatbuff(_FILTERS[0],jump_identification(adr));
  876.         strcatbuff(_FILTERS[0],"*");
  877.         break;
  878.         //
  879.       case 7:    // autoriser ce rΘpertoire
  880.         {
  881.           int i=strlen(fil)-1;
  882.           while((fil[i]!='/') && (i>0)) i--;
  883.           if (fil[i]=='/') {
  884.             HT_INSERT_FILTERS0;    // insΘrer en 0                                
  885.             strcpybuff(_FILTERS[0],"+");
  886.             strcatbuff(_FILTERS[0],jump_identification(adr));
  887.             if (*fil!='/') strcatbuff(_FILTERS[0],"/");
  888.             strncatbuff(_FILTERS[0],fil,i+1);
  889.             strcatbuff(_FILTERS[0],"*[file]");
  890.           }
  891.         }
  892.         
  893.         break;
  894.         
  895.       case 50:    // on fait rien
  896.         break;
  897.       }  // switch 
  898.                               
  899.     }  // test du wizard sur l'url
  900.   }  // fin du test wizard..
  901.  
  902.   // -------------------- PHASE 5 --------------------
  903.  
  904.   // lien non autorisΘ, peut-on juste le tester?
  905.   if (just_test_it) {
  906.     if (forbidden_url==1) {
  907.       if (opt->travel&256) {    // tester tout de mΩme
  908.         if (strfield(adr,"ftp://")==0
  909. #if HTS_USEMMS
  910.                     && strfield(adr,"mms://")==0
  911. #endif
  912.                     ) {    // PAS ftp!
  913.           forbidden_url=1;    // oui oui toujours interdit (note: sert α rien car ==1 mais c pour comprendre)
  914.           *just_test_it=1;     // mais on teste
  915.           if ((opt->debug>1) && (opt->log!=NULL)) {
  916.             fspc(opt->log,"debug"); fprintf(opt->log,"Testing link %s%s"LF,adr,fil);
  917.           }
  918.         }
  919.       }
  920.     }
  921.     //adr[0]='\0';  // cancel
  922.   }
  923.  
  924.   // -------------------- FINAL PHASE --------------------
  925.   // Test if the "Near" test won
  926.   if (may_set_prio_to && forbidden_url == 0) {
  927.     *set_prio_to = may_set_prio_to;
  928.   }
  929.  
  930.   return forbidden_url;
  931. #undef _FILTERS
  932. #undef _FILTERS_PTR
  933. #undef _ROBOTS
  934. }
  935.  
  936. int hts_acceptmime(httrackp* opt,
  937.                    int ptr,int lien_tot,lien_url** liens,
  938.                    char* adr,char* fil,
  939.                    char* mime) 
  940. {
  941. #define _FILTERS     (*opt->filters.filters)
  942. #define _FILTERS_PTR (opt->filters.filptr)
  943. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  944.   int forbidden_url = -1;
  945.   char* mdepth="";
  946.   int jokDepth = 0;
  947.   int jok = 0;
  948.  
  949.   /* Authorized ? */
  950.   jok  = fa_strjoker(/*mime*/1, _FILTERS, *_FILTERS_PTR, mime, NULL, NULL, &jokDepth);
  951.   if (jok != 0) {
  952.     mdepth = _FILTERS[jokDepth];
  953.     if (jok == 1) {   // autorisΘ
  954.       forbidden_url=0;  // URL autorisΘe
  955.       if ((opt->debug>1) && (opt->log!=NULL)) {
  956.         fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) explicit authorized (%s) link %s%s: mime '%s'"LF,mdepth,adr,fil,mime);
  957.         test_flush;
  958.       }
  959.     } else if (jok == -1) {  // forbidden
  960.       forbidden_url=1;   // URL interdite
  961.       if ((opt->debug>1) && (opt->log!=NULL)) {
  962.         fspc(opt->log,"debug"); fprintf(opt->log,"(wizard) explicit forbidden (%s) link %s%s: mime '%s'"LF,mdepth,adr,fil,mime);
  963.         test_flush;
  964.       }
  965.     }  // sinon on touche α rien
  966.   }
  967.   /* userdef test */
  968. #if HTS_ANALYSTE
  969.   if (hts_htmlcheck_check_mime != NULL) {
  970.     int test_url=hts_htmlcheck_check_mime(adr,fil,mime,forbidden_url);
  971.     if (test_url!=-1) {
  972.       forbidden_url=test_url;
  973.     }
  974.   }
  975. #endif
  976.   return forbidden_url;
  977. #undef _FILTERS
  978. #undef _FILTERS_PTR
  979. #undef _ROBOTS
  980. }
  981.  
  982. // tester taille
  983. int hts_testlinksize(httrackp* opt,
  984.                      char* adr,char* fil,
  985.                      LLint size) {
  986.   int jok=0;
  987.   if (size>=0) {
  988.     char BIGSTK l[HTS_URLMAXSIZE*2];
  989.     char BIGSTK lfull[HTS_URLMAXSIZE*2];
  990.     if (size>=0) {
  991.       LLint sz=size;
  992.       int size_flag=0;
  993.       
  994.       // former URL complΦte du lien actuel
  995.       strcpybuff(l,jump_identification(adr));
  996.       if (*fil!='/') strcatbuff(l,"/");
  997.       strcatbuff(l,fil);
  998.       //
  999.       if (!link_has_authority(adr))
  1000.         strcpybuff(lfull,"http://");
  1001.       else
  1002.         lfull[0]='\0';
  1003.       strcatbuff(lfull,adr);
  1004.       if (*fil!='/') strcatbuff(l,"/");
  1005.       strcatbuff(lfull,fil);
  1006.       
  1007.       // filters, 0=sait pas 1=ok -1=interdit
  1008.       {
  1009.         int jokDepth1=0,jokDepth2=0;
  1010.         int jok1=0,jok2=0;
  1011.         LLint sz1=size,sz2=size;
  1012.         int size_flag1=0,size_flag2=0;
  1013.         jok1  = fa_strjoker(/*url*/0, *opt->filters.filters,*opt->filters.filptr,lfull,&sz1,&size_flag1,&jokDepth1);
  1014.         jok2 =  fa_strjoker(/*url*/0, *opt->filters.filters,*opt->filters.filptr,l,    &sz2,&size_flag2,&jokDepth2);
  1015.         if (jok2 == 0) {      // #2 doesn't know
  1016.           jok = jok1;        // then, use #1
  1017.           sz = sz1;
  1018.           size_flag = size_flag1;
  1019.         } else if (jok1 == 0) {  // #1 doesn't know
  1020.           jok = jok2;        // then, use #2
  1021.           sz = sz2;
  1022.           size_flag = size_flag2;
  1023.         } else if (jokDepth1 >= jokDepth2) { // #1 matching rule is "after" #2, then it is prioritary
  1024.           jok = jok1;
  1025.           sz = sz1;
  1026.           size_flag = size_flag1;
  1027.         } else {                              // #2 matching rule is "after" #1, then it is prioritary
  1028.           jok = jok2;
  1029.           sz = sz2;
  1030.           size_flag = size_flag2;
  1031.         } 
  1032.       }
  1033.       
  1034.  
  1035.       // log
  1036.       if (jok==1) {
  1037.         if ((opt->debug>1) && (opt->log!=NULL)) {
  1038.           fspc(opt->log,"debug"); fprintf(opt->log,"File confirmed (size test): %s%s ("LLintP")"LF,adr,fil,(LLint)(size));
  1039.         }
  1040.       } else if (jok==-1) {
  1041.         if (size_flag) {        /* interdit α cause de la taille */
  1042.           if ((opt->debug>1) && (opt->log!=NULL)) {
  1043.             fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled due to its size: %s%s ("LLintP", limit: "LLintP")"LF,adr,fil,(LLint)(size),(LLint)(sz));
  1044.           }
  1045.         } else {
  1046.           jok=1;
  1047.         }
  1048.       }
  1049.     }
  1050.   }
  1051.   return jok;
  1052. }
  1053.  
  1054.  
  1055.  
  1056. #undef test_flush
  1057. #undef urladr
  1058. #undef urlfil
  1059.  
  1060. #undef HT_INSERT_FILTERS0
  1061.  
  1062.